package net.qiqbframework.persisthanding;


import lombok.extern.slf4j.Slf4j;
import net.qiqbframework.common.utils.StringUtil;
import net.qiqbframework.config.ConfigurationException;
import net.qiqbframework.messaging.Message;
import net.qiqbframework.messaging.annotation.ExecutableHandlerWrapper;
import net.qiqbframework.messaging.annotation.MessageExecutableHandler;
import net.qiqbframework.messaging.annotation.WrappedMessageExecutableHandler;
import net.qiqbframework.messaging.task.CurrentMessageTask;
import net.qiqbframework.messaging.task.MessageTask;

import javax.annotation.Nonnull;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.HashSet;
import java.util.Optional;
import java.util.Set;

public class PersistExecutableHandlerWrapper implements ExecutableHandlerWrapper {

    @Override
    public MessageExecutableHandler wrap(@Nonnull MessageExecutableHandler original) {

        final Optional<Object> routingBizIdentifierNaming = original.attribute(PersistHandlerAnnotationAttributes.ROUTING_AGGREGATE_NAME);
        if (routingBizIdentifierNaming.isPresent()) {
            return new PersistMessageExecutableHandlerImpl(original);
        }
        return original;
    }

    @Slf4j
    private static class PersistMessageExecutableHandlerImpl
            extends WrappedMessageExecutableHandler
            implements PersistExecutableHandler {

        private Class<?> aggregateType;

        private final PersistType persistType;

        private String aggregateName;

        private PersistMessageExecutableHandlerImpl(MessageExecutableHandler delegate) {
            super(delegate);
            // 获取返回值，
            final Optional<Method> originalMethodOptional = delegate.unwrap(Method.class);
            if (originalMethodOptional.isEmpty()) {
                throw new ConfigurationException("找不到方法");
            }
            final Method method = originalMethodOptional.get();

            boolean supportBatch = (boolean) delegate.attribute(PersistHandlerAnnotationAttributes.SUPPORT_BATCH).orElseThrow();

            if (supportBatch) {
                // 获取方法的返回类型
                Type[] parameterTypes = method.getGenericParameterTypes();

                for (Type type : parameterTypes) {
                    if (type instanceof ParameterizedType) {
                        ParameterizedType paramType = (ParameterizedType) type;
                        // 获取实际的类型参数
                        Type[] actualTypeArguments = paramType.getActualTypeArguments();
                        for (Type actualType : actualTypeArguments) {
                            this.aggregateType = (Class<?>) actualType;
                        }
                    }
                }
                if (this.aggregateType == null) {
                    final ConfigurationException configurationException = new ConfigurationException("The method [%s] modified by @ LoadHandler unable to confirm aggregation root type".formatted(method));
                    log.error("被 @LoadHandler 修饰方法[{}]无法确认聚合根类型。", method, configurationException);
                    throw configurationException;

                }
            } else {
                this.aggregateType = method.getParameters()[0].getType();

            }
            Object aggregateNameAttr = delegate.attribute(PersistHandlerAnnotationAttributes.ROUTING_AGGREGATE_NAME).orElse(null);
            if (aggregateNameAttr == null) {
                aggregateName = aggregateType.getName();
            } else {

                aggregateName = aggregateNameAttr.toString();
                if (StringUtil.isEmpty(aggregateName)) {
                    aggregateName = aggregateType.getName();
                }
            }

            persistType = (PersistType) delegate.attribute(PersistHandlerAnnotationAttributes.TYPE).orElseThrow();

        }

        @Override
        public boolean canHandle(@Nonnull Message<?> message) {
            if (message instanceof PersistMessage<?> persistMessage &&
                    (aggregateType.equals(persistMessage.getPayload().getClass()) || "*".equals(aggregateName))) {
                if (persistType == PersistType.ALL) {
                    return true;
                }
                if (persistMessage.isDeleted()) {
                    return persistType == PersistType.REMOVE;
                }
                if (persistType == PersistType.SAVE) {
                    return true;
                }
                return persistMessage.isNew() ? persistType == PersistType.ADD : persistType == PersistType.MODIFY;
            }
            return false;
        }

        @Override
        public Object handle(@Nonnull Message<?> message, Object target) throws Exception {
            if ("*".equals(aggregateName)) {
                final Object handle = super.handle(message, target);
                return handle;
            }
            final Optional<MessageTask<?>> parent = CurrentMessageTask.get().parent();
            if (parent.isPresent()) {
                final Object persistAggregateRootCache = parent.get().getResource("_persistAggregateRootCache");
                if (persistAggregateRootCache != null) {
                    if (((Set<?>) persistAggregateRootCache).contains(message.getPayload())) {

                        return null;
                    }
                }
            }
            final Object handle = super.handle(message, target);

            parent.ifPresent(messageTask -> messageTask.getOrComputeResource("_persistAggregateRootCache", r -> new HashSet<>()).add(message.getPayload()));
            return handle;
        }

        @Override
        public String aggregateName() {
            return aggregateName;
        }

        @Override
        public Class<?> aggregateType() {
            return aggregateType;
        }
    }
}
